package com.smart.speaker.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.util.Collections;
import java.util.List;

public class JsonUtils {

    private static ObjectMapper objectMapper;

    public static void init(ObjectMapper objectMapper) {
        JsonUtils.objectMapper = objectMapper;
    }

    public static <T> T parseJsonToObj(String jsonStr, Class<T> clazz) {
        try {
            return objectMapper.readerFor(clazz).readValue(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public static <T> T parseJsonToObj(String jsonStr, TypeReference<T> type) {
        try {
            return objectMapper.readValue(jsonStr, type);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public static <T> List<T> parseJsonToList(String jsonStr, Class<T> clazz) {
        if (clazz == null) {
            return Collections.emptyList();
        }
        try {
            return objectMapper.readerForListOf(clazz).readValue(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public static JsonNode parseJsonToJsonNode(String jsonStr) {
        try {
            return objectMapper.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(jsonStr, e);
        }
    }

    public static String formatObjToJson(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(e);
        }
    }

    public static <T> T convertToPojo(JsonNode jsonNode, Class<T> clazz) {
        try {
            return objectMapper.treeToValue(jsonNode, clazz);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(e);
        }
    }

    public static <T> T convertToPojo(JsonNode jsonNode, Class<T> clazz, Class<?>... types) {
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(clazz, types);
            return objectMapper.treeToValue(jsonNode, javaType);
        } catch (JsonProcessingException e) {
            throw new JsonParseException(e);
        }
    }

    public static ObjectNode createObjectNode() {
        return objectMapper.createObjectNode();
    }

    private static class JsonParseException extends RuntimeException {

        public JsonParseException(String msg) {
            super(msg);
        }

        public JsonParseException(String msg, Throwable cause) {
            super(msg, cause);
        }

        public JsonParseException(Throwable cause) {
            super(cause);
        }
    }
}
